package com.flowplan.todo.service;

import com.flowplan.auth.repository.SysUserRepository;
import com.flowplan.entity.SysUser;
import com.flowplan.entity.Todo;
import com.flowplan.entity.enums.TodoStatus;
import com.flowplan.entity.enums.TodoType;
import com.flowplan.project.repository.ProjectRepository;
import com.flowplan.todo.dto.TodoCreateRequest;
import com.flowplan.todo.dto.TodoResponse;
import com.flowplan.todo.dto.TodoUpdateRequest;
import com.flowplan.todo.repository.TodoRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 待办服务实现类
 * 
 * @author FlowPlan Team
 */
@Slf4j
@Service
public class TodoService {
    
    @Autowired
    private TodoRepository todoRepository;
    
    @Autowired
    private ProjectRepository projectRepository;
    
    @Autowired
    private SysUserRepository userRepository;
    
    /**
     * 创建待办
     */
    @Transactional
    public TodoResponse createTodo(TodoCreateRequest request, Long reporterId) {
        log.info("用户 {} 创建待办: {}", reporterId, request.getTitle());
        
        // 验证项目是否存在
        if (!projectRepository.existsById(request.getProjectId())) {
            throw new RuntimeException("项目不存在");
        }
        
        // 验证报告人是否存在
        if (!userRepository.existsById(reporterId)) {
            throw new RuntimeException("报告人不存在");
        }
        
        // 如果指定了负责人，验证负责人是否存在
        if (request.getAssigneeId() != null && !userRepository.existsById(request.getAssigneeId())) {
            throw new RuntimeException("负责人不存在");
        }
        
        // 创建待办实体
        Todo todo = Todo.builder()
                .projectId(request.getProjectId())
                .title(request.getTitle())
                .description(request.getDescription())
                .status(TodoStatus.TODO)
                .priority(request.getPriority())
                .todoType(request.getTodoType())
                .assigneeId(request.getAssigneeId())
                .reporterId(reporterId)
                .dueDate(request.getDueDate())
                .estimatedHours(request.getEstimatedHours())
                .build();
        
        Todo savedTodo = todoRepository.save(todo);
        
        log.info("待办创建成功，ID: {}", savedTodo.getId());
        return convertToResponse(savedTodo);
    }
    
    /**
     * 更新待办
     */
    @Transactional
    public TodoResponse updateTodo(Long todoId, TodoUpdateRequest request, Long userId) {
        log.info("用户 {} 更新待办 {}", userId, todoId);
        
        Todo todo = todoRepository.findById(todoId)
                .orElseThrow(() -> new RuntimeException("待办不存在"));
        
        // 只有待办的负责人、报告人或项目创建者才能更新待办
        if (!canModifyTodo(todo, userId)) {
            throw new RuntimeException("无权限更新此待办");
        }
        
        // 更新待办信息
        if (request.getTitle() != null) {
            todo.setTitle(request.getTitle());
        }
        
        if (request.getDescription() != null) {
            todo.setDescription(request.getDescription());
        }
        
        if (request.getStatus() != null) {
            todo.setStatus(request.getStatus());
        }
        
        if (request.getPriority() != null) {
            todo.setPriority(request.getPriority());
        }
        
        if (request.getTodoType() != null) {
            todo.setTodoType(request.getTodoType());
        }
        
        if (request.getAssigneeId() != null) {
            if (!userRepository.existsById(request.getAssigneeId())) {
                throw new RuntimeException("负责人不存在");
            }
            todo.setAssigneeId(request.getAssigneeId());
        }
        
        if (request.getDueDate() != null) {
            todo.setDueDate(request.getDueDate());
        }
        
        if (request.getEstimatedHours() != null) {
            todo.setEstimatedHours(request.getEstimatedHours());
        }
        
        if (request.getActualHours() != null) {
            todo.setActualHours(request.getActualHours());
        }
        
        Todo updatedTodo = todoRepository.save(todo);
        
        log.info("待办更新成功，ID: {}", todoId);
        return convertToResponse(updatedTodo);
    }
    
    /**
     * 删除待办
     */
    @Transactional
    public void deleteTodo(Long todoId, Long userId) {
        log.info("用户 {} 删除待办 {}", userId, todoId);
        
        Todo todo = todoRepository.findById(todoId)
                .orElseThrow(() -> new RuntimeException("待办不存在"));
        
        // 只有待办的报告人或项目创建者才能删除待办
        if (!canDeleteTodo(todo, userId)) {
            throw new RuntimeException("无权限删除此待办");
        }
        
        todoRepository.delete(todo);
        log.info("待办删除成功，ID: {}", todoId);
    }
    
    /**
     * 获取待办详情
     */
    @Transactional(readOnly = true)
    public TodoResponse getTodo(Long todoId) {
        Todo todo = todoRepository.findById(todoId)
                .orElseThrow(() -> new RuntimeException("待办不存在"));
        
        return convertToResponse(todo);
    }
    
    /**
     * 分页查询待办列表
     */
    @Transactional(readOnly = true)
    public Page<TodoResponse> getTodos(Long projectId, TodoStatus status, Long assigneeId, 
                                     TodoType todoType, String keyword, int page, int size) {
        Pageable pageable = PageRequest.of(page, size);
        
        Page<Todo> todoPage = todoRepository.findTodosWithConditions(
                projectId, status, assigneeId, todoType, keyword, pageable);
        
        return todoPage.map(this::convertToResponse);
    }
    
    /**
     * 获取用户相关的待办列表
     */
    @Transactional(readOnly = true)
    public List<TodoResponse> getUserTodos(Long userId) {
        List<Todo> todos = todoRepository.findTodosByUser(userId);
        return todos.stream()
                .map(this::convertToResponse)
                .collect(Collectors.toList());
    }
    
    /**
     * 获取项目下的待办列表
     */
    @Transactional(readOnly = true)
    public List<TodoResponse> getProjectTodos(Long projectId) {
        List<Todo> todos = todoRepository.findByProjectIdOrderByCreateTimeDesc(projectId);
        return todos.stream()
                .map(this::convertToResponse)
                .collect(Collectors.toList());
    }
    
    /**
     * 获取即将到期的待办
     */
    @Transactional(readOnly = true)
    public List<TodoResponse> getTodosNearDeadline() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime deadlineLimit = now.plusHours(24);
        
        List<Todo> todos = todoRepository.findTodosNearDeadline(now, deadlineLimit);
        return todos.stream()
                .map(this::convertToResponse)
                .collect(Collectors.toList());
    }
    
    /**
     * 获取已过期的待办
     */
    @Transactional(readOnly = true)
    public List<TodoResponse> getOverdueTodos() {
        LocalDateTime now = LocalDateTime.now();
        
        List<Todo> todos = todoRepository.findOverdueTodos(now);
        return todos.stream()
                .map(this::convertToResponse)
                .collect(Collectors.toList());
    }
    
    /**
     * 更新待办状态
     */
    @Transactional
    public TodoResponse updateTodoStatus(Long todoId, TodoStatus status, Long userId) {
        log.info("用户 {} 更新待办 {} 状态为 {}", userId, todoId, status);
        
        Todo todo = todoRepository.findById(todoId)
                .orElseThrow(() -> new RuntimeException("待办不存在"));
        
        if (!canModifyTodo(todo, userId)) {
            throw new RuntimeException("无权限更新此待办状态");
        }
        
        todo.setStatus(status);
        
        // 如果标记为完成，记录完成时间
        if (status == TodoStatus.DONE) {
            // 这里可以添加完成时间字段到实体中
        }
        
        Todo updatedTodo = todoRepository.save(todo);
        
        log.info("待办状态更新成功，ID: {}, 新状态: {}", todoId, status);
        return convertToResponse(updatedTodo);
    }
    
    /**
     * 检查用户是否可以修改待办
     */
    private boolean canModifyTodo(Todo todo, Long userId) {
        // 待办的负责人、报告人可以修改
        if (userId.equals(todo.getAssigneeId()) || userId.equals(todo.getReporterId())) {
            return true;
        }
        
        // 项目创建者可以修改
        return projectRepository.findById(todo.getProjectId())
                .map(project -> userId.equals(project.getCreatorId()))
                .orElse(false);
    }
    
    /**
     * 检查用户是否可以删除待办
     */
    private boolean canDeleteTodo(Todo todo, Long userId) {
        // 待办的报告人可以删除
        if (userId.equals(todo.getReporterId())) {
            return true;
        }
        
        // 项目创建者可以删除
        return projectRepository.findById(todo.getProjectId())
                .map(project -> userId.equals(project.getCreatorId()))
                .orElse(false);
    }
    
    /**
     * 转换为响应DTO
     */
    private TodoResponse convertToResponse(Todo todo) {
        // 获取相关用户信息
        String assigneeName = null;
        if (todo.getAssigneeId() != null) {
            assigneeName = userRepository.findById(todo.getAssigneeId())
                    .map(SysUser::getUsername)
                    .orElse(null);
        }
        
        String reporterName = userRepository.findById(todo.getReporterId())
                .map(SysUser::getUsername)
                .orElse(null);
        
        String projectName = projectRepository.findById(todo.getProjectId())
                .map(project -> project.getProjectName())
                .orElse(null);
        
        // 计算是否过期
        boolean isOverdue = todo.getDueDate() != null && 
                          todo.getDueDate().isBefore(LocalDateTime.now()) &&
                          todo.getStatus() != TodoStatus.DONE;
        
        // 计算进度
        int progress = calculateProgress(todo.getStatus());
        
        return TodoResponse.builder()
                .id(todo.getId())
                .projectId(todo.getProjectId())
                .projectName(projectName)
                .title(todo.getTitle())
                .description(todo.getDescription())
                .status(todo.getStatus())
                .priority(todo.getPriority())
                .todoType(todo.getTodoType())
                .assigneeId(todo.getAssigneeId())
                .assigneeName(assigneeName)
                .reporterId(todo.getReporterId())
                .reporterName(reporterName)
                .dueDate(todo.getDueDate())
                .estimatedHours(todo.getEstimatedHours())
                .actualHours(todo.getActualHours())
                .createTime(todo.getCreateTime())
                .updateTime(todo.getUpdateTime())
                .isOverdue(isOverdue)
                .progress(progress)
                .build();
    }
    
    /**
     * 根据状态计算进度
     */
    private int calculateProgress(TodoStatus status) {
        switch (status) {
            case TODO:
                return 0;
            case IN_PROGRESS:
                return 50;
            case DONE:
                return 100;
            case BLOCKED:
                return 25;
            default:
                return 0;
        }
    }
}